import { ArrayMethods } from "./arrayMethods";
import Dep from "./dep";
export function observer(data) {
    if (typeof data !== "object" || data === null) {
        return data;
    }
    return new Observer(data);
}

function defineReactive(data, key, value) {
    /**
     * 这里可以看出每一个变量一个dep
     * watcher 有 3 种，$watcher、computed、更新
     * 这里将 dep 和 watcher 进行双向绑定
     * 在 set 里面触发更新
     */
    const dep = new Dep()
    const childDep = observer(value); //深度代理

    Object.defineProperty(data, key, {
        get() {
            // 数据双向绑定 -赋值是更新视图 先set 后get
            // 添加新watch监听数据 --执行顺序是 
            // 1.先做数据劫持 
            // 2.向dep里面添加watcher 
            // 3. 触发数据更新 
            // 4.触发get(触发watcher里面的更新，再次存储) 
            // todo 细致的targat 更新流程
            if (Dep.target) {
                dep.depend()
                if (childDep.dep) {
                    childDep.dep.depend()
                }
            }
            console.log("get", dep, value);
            return value;
        },
        set(newVal) {
            console.log('set', newVal);
            if (newVal === value) return;
            // 解决赋值没有监听问题
            observer(newVal);
            value = newVal;

            // 更新watch监听数据
            dep.notify()
        },
    });
}

class Observer {
    constructor(value) {
        // 对数据添加自定义方法，用于数组方法处理
        Object.defineProperty(value, "__ob__", {
            enumerable: false,
            value: this,
        });
        this.dep = new Dep();
        if (Array.isArray(value)) {
            value.__proto__ = ArrayMethods;
            // 处理数组对象
            this.observerArray(value);
        } else {
            this.walk(value);
        }
    }

    walk(data) {
        let keys = Object.keys(data);
        for (let i = 0; i < keys.length; i++) {
            const key = keys[i];
            const value = data[key];
            defineReactive(data, key, value);
        }
    }

    observerArray(data) {
        for (let i = 0; i < data.length; i++) {
            observer(data[i]);
        }
    }
}

/**
 * 数组依赖收集
 * 1. 给每个对象添加dep
 * 2. 获取数组值的时候，会调用get方法，要让当前数组触发渲染water
 *  2.1 获取当前dep
 *  2.2 当前面对数组取值时候，让dep建筑watcher
 * 3. 更新数组的时候 调用push等方法，找到watcher进行更新
 */